﻿// 4548. 猴子和香蕉.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
/*
https://www.acwing.com/problem/content/4551/

研究员正在测试猴子的智商。

他们将一串香蕉放到很高的地方，并给猴子一些积木。

如果猴子足够聪明，它应该能够通过将一个积木放到另一个积木上的方式，不断向上堆叠积木，建成一座高塔，并爬上去取得香蕉。

研究员一共给猴子提供了 n种不同类型的积木，每种积木的供应数量无限多。

在堆叠过程中，猴子可以随意摆弄积木，自由决定积木的哪个面作为底面，以及积木的具体摆放朝向。

在堆叠时满足的条件是：位于下面的积木的长和宽必须严格大于位于上面的积木的长和宽。

堆叠的积木高度当然是越高越好，请你计算最大可能高度。

输入格式
输入包含多组测试数据。

每组数据第一行包含整数 n。

接下来 n 行，每行包含三个整数 xi,yi,zi，表示一种积木的长宽高。

当输入 n=0
 时，输入结束。

输出格式
每组数据输出一行结果，格式为 Case i: maximum height = x，其中 i为组别编号（从 1开始），x为最大可能高度。

数据范围
输入最多包含 10 组数据。
1≤n≤30,
1≤xi,yi,zi≤40000。

输入样例：
1
10 20 30
2
6 8 10
5 5 5
7
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
0
输出样例：
Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342
*/

const int N = 200;
struct BLOCK {
	int x, y, z;
}block[N];
int blockIdx;
int n;	int t;

void insert(int a, int b, int c) {
	block[++blockIdx].x = a;
	block[blockIdx].y = b;
	block[blockIdx].z = c;
}

bool cmp(const struct BLOCK& a, const struct BLOCK& b) {
	if (a.x > b.x) return true;
	else if (a.x == b.x) return a.y > b.y;
	return false;
}

int dp[N];


void solve() {
	memset(dp, 0, sizeof dp);
	int ans = 0;
	for (int i = 1; i <= blockIdx; i++) {
		dp[i] = block[i].z;
		for (int j = 0; j < i; j++) {
			if (block[i].x < block[j].x && block[i].y < block[j].y)
				dp[i] = max(dp[i], dp[j] + block[i].z);
		}
		ans = max(ans, dp[i]);
	}

	cout << "Case " << ++t << ": " << "maximum height = " << ans << endl;
}


int main()
{

	while (cin >> n) {
		if (0 == n) break;
		blockIdx = 0;
		for (int i = 1; i <= n; i++) {
			int x, y, z;
			cin >> x >> y >> z;
			insert(x, y, z); insert(x, z, y); insert(y, x, z); insert(y, z, x); insert(z, x, y); insert(z, y, x);
		}
		sort(block + 1, block + blockIdx + 1, cmp);

		solve();
	}


	return 0;
}

